package progetto;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;

import peersim.config.Configuration;
import peersim.core.Network;
import peersim.core.Node;
import peersim.graph.Graph;
import peersim.reports.GraphObserver;
import peersim.util.FileNameGenerator;

public class GraphInfObserver extends GraphObserver{

	/**
	 * This class prints to files the topology wiring using a Gnuplot friendly
	 * syntax. Uses the {@link peersim.graph.Graph} interface to visit the topology.
	 * 
	 * Creates two file at each run, one with the the topology wiring, and the other one with the node infected.
	 * 
	 * @author Catia Prandi
	 * 
	 */

	// ------------------------------------------------------------------------
	// Parameters
	// ------------------------------------------------------------------------

	/**
	 * The filename base to print out the topology relations.
	 * 
	 * @config
	 */
	private static final String PAR_FILENAME_BASE = "file_mobility";

	/**
	 * The coordinate protocol to look at.
	 * 
	 * @config
	 */
	private static final String PAR_COORDINATES_PROT = "coord_protocol";


	/**
	 * 
	 * @config
	 */
	private static final String PAR_STATUS_PROT = "status_protocol";
	// ------------------------------------------------------------------------
	// Fields
	// ------------------------------------------------------------------------


	private static final String PAR_FILE_INF = "file_mobility_inf";

	/**
	 * Topology filename. Obtained from config property
	 * {@link #PAR_FILENAME_BASE}.
	 */
	private final String graphFilename;

	/**
	 * Utility class to generate incremental indexed filenames from a common
	 * base given by {@link #graphFilename}.
	 */
	private final FileNameGenerator fng;

	private final FileNameGenerator fngI;

	/**
	 * Status protocol identifier. Obtained from config property
	 * {@link #PAR_STATUS_PROT}.
	 */
	private final int statusPid;

	/**
	 * Coordinate protocol identifier. Obtained from config property
	 * {@link #PAR_COORDINATES_PROT}.
	 */
	private final int coordPid;


	private final String graphFileInf;

	// ------------------------------------------------------------------------
	// Constructorin
	// ------------------------------------------------------------------------
	/**
	 * Standard constructor that reads the configuration parameters. Invoked by
	 * the simulation engine.
	 * 
	 * @param prefix
	 *            the configuration prefix for this class.
	 */
	public GraphInfObserver(String prefix) {
		super(prefix);
		coordPid = Configuration.getPid(prefix + "." + PAR_COORDINATES_PROT);
		statusPid = Configuration.getPid(prefix + "." + PAR_STATUS_PROT);
		graphFilename = Configuration.getString(prefix + "."
				+ PAR_FILENAME_BASE, "graph");
		graphFileInf = Configuration.getString(prefix + "."
				+ PAR_FILE_INF, "infect");
		fng = new FileNameGenerator(graphFilename, ".dat");
		fngI = new FileNameGenerator(graphFileInf, ".dat");
	}

	// Control interface method.
	public boolean execute() {
		
		boolean allInfected = false;
		
		try {
			updateGraph();

			System.out.print(name + ": ");

			// initialize output streams
			String fname = fng.nextCounterName();
			FileOutputStream fos = new FileOutputStream(fname);
			System.out.println("Writing to file " + fname);
			PrintStream pstrMobility = new PrintStream(fos);

			String fnameInf = fngI.nextCounterName();
			FileOutputStream fosInf = new FileOutputStream(fnameInf);
			System.out.println("Writing to file " + fnameInf);
			PrintStream pstrMobInf = new PrintStream(fosInf);


			allInfected = graphToFile(g, pstrMobility,pstrMobInf,coordPid, statusPid);

			fos.close();
		} catch (IOException e) {
			throw new RuntimeException(e);
		}

		return allInfected;
		
	}

	/**
	 * Utility method: prints out data to plot the topology using gnuplot a
	 * gnuplot style.
	 * 
	 * @param g
	 *            current graph.
	 * @param ps_mobility
	 *            a {@link java.io.PrintStream} object to write to.
	 * @param coordPid
	 *            coordinate protocol identifier.
	 * @param statusPid
	 *            status protocol identifier.
	 */
	private static boolean graphToFile(Graph g, PrintStream ps_mobility, PrintStream ps_inf, int coordPid, int statusPid) {
		//number of infected node
		int numInfected = 0;
		
		for (int i = 0; i < g.size(); i++) {
			Node current = (Node) g.getNode(i);
	
			double x_to = ((DynamicCoordinates) current.getProtocol(coordPid)).getX();
			double y_to = ((DynamicCoordinates) current.getProtocol(coordPid)).getY();


			boolean flagInfected =  ((NodeStatus)current.getProtocol(statusPid)).isInfected();
			if(flagInfected) {
				
				numInfected++;
				//print the coordinates in the file of the infected nodes
				ps_inf.println(x_to + " " + y_to);
				ps_inf.println();
			}

			boolean flagNeighbours = false;
			for (int index : g.getNeighbours(i)) {
				flagNeighbours = true;
				Node n = (Node) g.getNode(index);
				double x_from = ((DynamicCoordinates) n.getProtocol(coordPid)).getX();
				double y_from = ((DynamicCoordinates) n.getProtocol(coordPid)).getY();
				//print the coordinates of the two node near in the graph file
				ps_mobility.println(x_to + " " + y_to);
				ps_mobility.println(x_from + " " + y_from);
				ps_mobility.println();
			}

			if(!flagNeighbours) {
				//print the coordinates of the node without neighbours
				ps_mobility.println(x_to + " " + y_to);
				ps_mobility.println();
			}
		}

		if(numInfected == Network.size())
			return true;

		return false;


	}
}


